<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>网上找了个插件，但是不好用</title>
		<script src="js/jquery-3.5.1.js" type="text/javascript" charset="utf-8"></script>
		<style>
			body,html{padding:0;margin:0;width:100%;height:100%;}
    </style>
	</head>
	<body>
		<div style="height:500px;margin:20px;">
			<!-- option必须带有 value 的值 -->
			<select id="magicsuggest" data-edit-select="1">
				<option value="1">哇哈哈</option>
				<option value="2">天天</option>
				<option value="3">xx</option>
				<option value="1">哇哈哈哇哈哈哇哈哈哇哈哈哇哈哈</option>
				<option value="2">天天</option>
				<option value="3">xx</option>
				<option value="1">哇哈哈</option>
				<option value="2">天天</option>
				<option value="3">xx</option>
				<option value="1">哇哈哈</option>
				<option value="2">天天</option>
				<option value="3">xx</option>
			</select>
		</div>
		<div style="height:1000px;"></div>
	</body>

	<!-- 下面这段代码，就是可编辑select，嗯，那个丑陋的样式，被我也写在里面了 -->
	<script type="text/javascript">
		$.fn.filterSelect = (function() {
			// 我就 很 纠结的，把样式内嵌在这里了，让你怎么改!!!!
			var isInit = false;

			function initCss() {
				isInit = true;
				var style = document.createElement("style");
				var csstext =
					'.m-input-select{display:inline-block;*display:inline;position:relative;-webkit-user-select:none;}\
                        \n.m-input-select ul, .m-input-select li{padding:0;margin:0;}\
                        \n.m-input-select .m-input{padding-right:22px;}\
                        \n.m-input-select .m-input-ico{position:absolute;right:0;top:0;width:22px;height:100%;background:url() no-repeat 50% 50%;}\
                        \n.m-input-select .m-list-wrapper{}\
                        \n.m-input-select .m-list{display:none;position:absolute;z-index:1;top:100%;left:0;right:0;max-width:100%;max-height:250px;overflow:auto;border-bottom:1px solid #ddd;}\
                        \n.m-input-select .m-list-item{cursor:default;padding:5px;margin-top:-1px;list-style:none;background:#fff;border:1px solid #ddd;border-bottom:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\
                        \n.m-input-select .m-list-item:hover{background:#2D95FF;}\
                        \n.m-input-select .m-list-item-active{background:#2D95FF;}';
				style = $("<style>" + csstext + "</style>")[0];
				// ie 竟然坑了...
				// if(style.styleSheet) {
				//     style.styleSheet.cssText = csstext;
				// }else{
				//     style.appendChild(document.createTextNode(csstext));
				// };

				var head = document.head || document.getElementsByTagName("head")[0];
				if (head.hasChildNodes()) {
					head.insertBefore(style, head.firstChild);
				} else {
					head.appendChild(style);
				};

			};

			return function() {
				!isInit && initCss();

				var $body = $("body");
				this.each(function(i, v) {
					var $sel = $(v),
						$div = $('<div class="m-input-select"></div>');
					var $input = $("<input type='text' class='m-input' />");
					// var $wrapper = $("<div class='m-list-wrapper'><ul class='m-list'></ul></div>");
					var $wrapper = $("<ul class='m-list'></ul>");
					$div = $sel.wrap($div).hide().addClass("m-select").parent();
					$div.append($input).append("<span class='m-input-ico'></span>").append($wrapper);

					// 遮罩层显示 + 隐藏
					var wrapper = {
						show: function() {
							$wrapper.show();
							this.$list = $wrapper.find(".m-list-item:visible");
							this.setIndex(this.$list.filter(".m-list-item-active"));
							this.setActive(this.index);
						},
						hide: function() {
							$wrapper.hide();
						},
						next: function() {
							return this.setActive(this.index + 1);
						},
						prev: function() {
							return this.setActive(this.index - 1);
						},
						$list: $wrapper.find(".m-list-item"),
						index: 0,
						$cur: [],
						setActive: function(i) {
							// 找到第1个 li，并且赋值为 active
							var $list = this.$list,
								size = $list.size();
							if (size <= 0) {
								this.$cur = [];
								return;
							}
							$list.filter(".m-list-item-active").removeClass("m-list-item-active");
							if (i < 0) {
								i = 0;
							} else if (i >= size) {
								i = size - 1;
							}
							this.index = i;
							this.$cur = $list.eq(i).addClass("m-list-item-active");
							this.fixScroll(this.$cur);
							return this.$cur;
						},
						fixScroll: function($elem) {
							// console.log($wrapper);
							var height = $wrapper.height(),
								top = $elem.position().top,
								eHeight = $elem.outerHeight();
							var scroll = $wrapper.scrollTop();
							// 因为 li 的 实际　top，应该要加上 滚上 的距离
							top += scroll;
							if (scroll > top) {
								$wrapper.scrollTop(top);
							} else if (top + eHeight > scroll + height) {
								// $wrapper.scrollTop(top + height - eHeight);
								$wrapper.scrollTop(top + eHeight - height);
							}
						},
						setIndex: function($li) {
							if ($li.size() > 0) {
								this.index = this.$list.index($li);
								$li.addClass("m-list-item-active").siblings().removeClass("m-list-item-active");
							} else {
								this.index = 0;
							}
						}
					};

					// input 的操作
					var operation = {
						// 文字更变了，更新 li, 最低效率的一种
						textChange: function() {
							val = $.trim($input.val());
							$wrapper.find(".m-list-item").each(function(i, v) {
								if (v.innerHTML.indexOf(val) >= 0) {
									$(v).show();
								} else {
									$(v).hide();
								}
							});
							wrapper.show();
						},
						// 设值
						setValue: function($li) {
							if ($li && $li.size() > 0) {
								var val = $.trim($li.html());
								$input.val(val).attr("placeholder", val);
								wrapper.setIndex($li);
								$sel.val($li.attr("data-value")).trigger("change");
							} else {
								$input.val(function(i, v) {
									return $input.attr("placeholder");
								});
							};
							wrapper.hide();
							this.offBody();
						},
						onBody: function() {
							var self = this;
							setTimeout(function() {
								self.offBody();
								$body.on("click", self.bodyClick);
							}, 10);
						},
						offBody: function() {
							$body.off("click", this.bodyClick);
						},
						bodyClick: function(e) {
							var target = e.target;
							if (target != $input[0] && target != $wrapper[0]) {
								wrapper.hide();
								operation.setValue();
								operation.offBody();
							}
						}
					};

					// 遍历 $sel 对象
					function resetOption() {
						var html = "",
							val = "";
						$sel.find("option").each(function(i, v) {
							if (v.selected && !val) {
								val = v.text;
							};
							html += '<li class="m-list-item' + (v.selected ? " m-list-item-active" : "") + '" data-value="' + v.value +
								'">' + v.text + '</li>';
						});
						$input.val(val);
						$wrapper.html(html);
					};
					$sel.on("optionChange", resetOption).trigger("optionChange");
					$sel.on("setEditSelectValue", function(e, val) {
						// console.log(val);
						var $all = $wrapper.find(".m-list-item"),
							$item;
						for (var i = 0, max = $all.size(); i < max; i++) {
							$item = $all.eq(i);
							if ($item.attr("data-value") == val) {
								operation.setValue($item);
								return;
							}
						}
					});

					// input 聚焦
					$input.on("focus", function() {
						this.value = "";
						operation.textChange();
						operation.onBody();
					}).on("input propertychange", function(e) {
						operation.textChange();
					}).on("keydown", function(e) {
						// 上 38, 下 40， enter 13
						switch (e.keyCode) {
							case 38:
								wrapper.prev();
								break;
							case 40:
								wrapper.next();
								break;
							case 13:
								operation.setValue(wrapper.$cur);
								break;
						}
					});

					$div.on("click", ".m-input-ico", function() {
						// 触发 focus 和 blur 事件
						// focus 是因为 input 有绑定
						// 而 blur，实际只是失去焦点而已，真正隐藏 wrapper 的是 $body 事件
						$wrapper.is(":visible") ? $input.blur() : ($input.val("").trigger("focus"));
					});

					// 选中
					$wrapper.on("click", ".m-list-item", function() {
						operation.setValue($(this));
						return false;
					});

					setTimeout(function() {
						// for ie
						wrapper.hide();
					}, 1)


				});

				return this;
			};
		})();
	</script>


	<!-- 这段代码，是遍历所有拥有 data-edit-select 属性的元素，并把他们变为可编辑 -->
	<script>
		// 使用了这个插件，select该怎么用就怎么用
		// 任何选择，同样会触发 select 的 更变的说【即select的值会同步更新】
		//
		var $select = $("select[data-edit-select]").filterSelect();
		// --> 这时候的  $select === $("#magicsuggest");
		// 也可以 用 $("#magicsuggest").on("change")，两者等价
		$select.on("change", function() {
			// console.log(this.value)
		});
		// 也可以通过 $("#magicsuggest").val() 拿到最新的值
		// 通过 $("#magicsuggest").trigger("setEditSelectValue", 2); 设置选中的值为 2
		// 通过 $("#magicsuggest").trigger("optionChange") 触发 更新 option 的值
	</script>
</html>
